// CSE-102 DSA Assignment - Implementation of UserID-Password-Authentification using hash tables (Code 2).
// Ankit Mittal - 2010015

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<malloc.h>

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int m;													//m=Number of slots in the hash table-
														//-Initial value of m does not matter-
														//-m will be updated after reading the file
														
float alpha = 0.56;										//SET VALUE of 0 < alpha <= 1
char * filename = "users.txt";							//File containing authentication data
														//Each line in the file contains a username-
														//-its corresponding password seperated by a-
														//-white space of two tabs between them.


struct user{	int nil;
				char userid[30];
				char passcode[30];
           };

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int hash_dash(int key)									//The Multiplication Method
{	float A=0.618;									
	float kA=key*A;
	int h = floor(m*(kA-(int)kA));
	return h;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int hash(int key, int i)								//Linear Probing			
{	int h = (hash_dash(key) + i)%m;
	return h; 
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int generatekey(char * u)								//Generating key as the sum of ascii value of each character in the string
{	char c;
	int i=0,ascii=0;
	for(c=u[i];c!='\0';c=u[++i])
		{	ascii+=c;				
		}
	return(ascii);
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void search_hash_table(struct user * table)				//Input a username, Obtain its password from the hash table, Input the password, Match
{	char password[30], username[30], input[30];
	int key, attempt=0;
	int i=0,j;
	struct user ptr;
	printf("\n\nEnter the User ID: ");
	scanf("%s",username);	
	//printf("herehere");
	key=generatekey(username);
	//printf("herehere");
	hashing:
	j=hash(key,i);
	//printf("---%d---",table[j].nil);
	//printf("herehere");
	ptr=table[j];
	
	if(table[j].nil)									//If the mapped slot is vacant
	{	printf("\nUser ID does not exist...\n");	
		search_hash_table(table);
		return;
	}
	
	else
	{	//printf("gggg");
		if(!strcmp(table[j].userid,username))				//If the username in the mapped slot matches our search
		{	strcpy(password,table[j].passcode);
		}
		else
		{	if(i==m)									//If username is not present in any slot
			{	printf("\nUser ID does not exist...\n");
				search_hash_table(table);
				return;
			}
			i++;
			goto hashing;
		}
	}	
	check:
	printf("\nEnter passcode: ");
	attempt++;
	scanf("%s",input);
	if(!strcmp(input,password))							//Comparing the actual password and the entered password
	{	printf("\nAuthentication Confirmed...");
		printf("\nThank You !!!\n\n");
	}
	else
	{	if(attempt!=3)
		{	printf("\nAuthentication Failed... Try Again...\nAttempts left: %d\n",3-attempt);
			goto check;
		}
		else
			printf("\nAuthentication failed... No attempts left...\n");
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

struct user * fill_hash_table(FILE * fp)	//Filling the hash table
{	
	char line[60], *p, *u, ch;
	int n=0,i,j=0,q;
	int key;
	struct user * table;
	fp = fopen(filename, "r");
	//printf("huhuhu");
	//fseek(fp,1,SEEK_CUR);
	if(fp==NULL)										//If file with this name does not exist
	{	printf("\nData not available...\n");
		exit(0);
	}
	while(!feof(fp))									//Counting number of entries in the file
	{	ch=getc(fp);
		if(ch=='\n')
			n++;
	}
	m=n/alpha;
	//m=14;
	//printf("mimimi");
	table=realloc(table,m*sizeof(struct user));
	//printf("!!!");
	for(q=0;q<m;q++)
	{	table[q].nil=1;
	}
	//printf("hiii");
	//m=n/alpha;
	//printf("A%dA%dA",n--,num);
	//getchar();
	//exit(0);
	//fseek(fp,20,SEEK_SET);
	//rewind(fp);
	fclose(fp);
	fp = fopen(filename, "r");
	while(1)
	{	//if(feof(fp)) break;								//If end of file has been reached
		fgets(line,60,fp);								//Reads one line at a time
		if(feof(fp)) break;								//If end of file has been reached
		//n++;
		u=strtok(line,"\t\t");							//Identifying the username and password in-
		p=strtok(NULL,"\t\t\n");						//-line as they are seperated by 2 tabs
		key=generatekey(u);
		i=0;											//i is the probe index
		hashing:
		j=hash(key,i);									//j is the hash value obtained from the hash function
		if(n>m)
		{	printf("\nUsernames more than number of slots in the hash table...\nCannot hash with open addressing...\nProgram Terminated...");
			getchar();									//When entire table has been searched in vain for a blank slot
			exit(0);
		}
		if(table[j].nil)								//If the slot is vacant
		{	table[j].nil=0;
			strcpy(table[j].userid,u);
			strcpy(table[j].passcode,p);
		}
		else
		{	i++;
			goto hashing;
		}
		printf("\n%s",table[j].userid);
		printf(" %s",table[j].passcode);
	}
	fclose(fp);											//Terminating the file pointer
	//printf("fill done");
	return table;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

int main()
{	int i;
	float f=0.5;
	struct user *table;
	FILE *fp;											//Declaring a file pointer
//	for(i=0;i<m;i++)
//	{	table[i].nil=1;
//	}
	//printf("%f",(7*f));
	table=fill_hash_table(fp);
	search_hash_table(table);
	getchar();
	return 0;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
